/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package mtvotingserver;

/**
 *
 * @author David Firth
 *
 * Buffer class used to store client Models when the voting is going on
 * has two conditions one which is to do with the buffer not being empty and
 * another to do with the buffer not being full.
 */

import java.util.concurrent.locks.* ;

public class ClientBuffer {

    private Lock theLock ;
    private Condition theBufferIsNotEmpty ;
    private Condition theBufferIsNotFull ;
    private ClientModel[] theBuffer ;
    private int theSize;
    private int theIn, theOut ;
    private int theNoOfItems ;

    public ClientBuffer(int size) {
        //initialises everything with a parameter being passed down for the
        //size of the array of ClientModels for the buffer
        theLock = new ReentrantLock() ;
        theBufferIsNotEmpty = theLock.newCondition() ;
        theBufferIsNotFull = theLock.newCondition() ;
        theSize = size ;
        theBuffer = new ClientModel[theSize];
        theIn = 0 ;
        theOut = 0 ;
        theNoOfItems = 0 ;
    }

    public void add(ClientModel x) {
        //method to add a clientModel to the buffer when it is unlocked
        try {
            theLock.lock() ;
            while (theNoOfItems == theSize)
            try { 
                theBufferIsNotFull.await() ;
            }
            catch(InterruptedException e){}
            
            theBuffer[theIn] = x;
            theIn = (theIn + 1) % theSize ;
            theNoOfItems++ ;
            theBufferIsNotEmpty.signal() ;
        } finally {
            theLock.unlock() ;
        }
    }

    public ClientModel remove() {
        //method to remove a client model from the buffer
        try {
            theLock.lock() ;
            while (theNoOfItems == 0)
            try { 
                theBufferIsNotEmpty.await() ;
            }
            catch(InterruptedException e){}

            ClientModel x = theBuffer[theOut] ;
            theOut = (theOut + 1) % theSize ;
            theNoOfItems-- ;
            theBufferIsNotFull.signal() ;
            return x ;
        } finally {
            theLock.unlock() ;
        }
    }

    public ClientModel confirm(ClientModel x) {
        //method to confirm a vote upon its second entry into the buffer
        try {
            theLock.lock() ;
            if (theNoOfItems == 0)
                return null;

            //go through the valid elements of the buffer, all the ones that
            //haven't been read
            for (int i = theOut; i != theIn; i = (++i)%theSize)
                //if the client model matches the param
                if (x.getClientIP().equals(theBuffer[i].getClientIP()) && 
                        (x.getClientPort() == theBuffer[i].getClientPort())) {
                    //confirm the vote
                    theBuffer[i].confirmVote(x.getClientVote());
                    ClientModel client = theBuffer[i];
                    //take the model out of the array
                    for (int j = i; j != theIn; j = (++j)%theSize) {
                        theBuffer[j] = theBuffer[(j + 1)%theSize];
                    }
                    //move the IN iterator by 1
                    theIn = (theIn - 1) % theSize;
                    //mark that there are less items in the buffer
                    theNoOfItems-- ;
                    theBufferIsNotFull.signal() ;
                    return client;
                }
            return null;
        } finally {
            theLock.unlock() ;
        }
    }
}

